这篇内容是在有道云旧笔记基础上重新整理的 技术实践 笔记。原始记录偏碎片化,这里补充了使用场景、阅读顺序和落地时需要注意的边界,方便以后在项目里快速复用。

适用场景 ​

  • 前端业务中需要快速处理数据、DOM、浏览器能力或通用工具函数时参考。
  • 把散落在项目里的小技巧抽成可复用代码片段,减少重复实现。
  • 排查兼容性和边界输入问题前,先用本文示例确认核心思路。

核心要点 ​

  • 正文已经按 「1. 数据库设计」、「1.1 user 表」、「1.2 role 表」、「1.3 permission 表」 等小节组织,阅读时可以先定位到当前问题对应的小节。
  • 保留了 28 段可直接参考的代码或命令,主要涉及 sql、typescript,复制前需要按当前项目路径、版本和变量名做调整。

好的,我将根据你之前提出的需求整理出一个完整的权限管理示例,包含用户、角色、权限的管理,并支持用户的个性化权限设置(增加或撤销某个权限)。以下是完整的示例:

1. 数据库设计 ​

我们首先设计 5 个表来管理用户、角色、权限以及个性化权限。

1.1 user 表 ​

存储用户信息。

1
2
3
4
5
6
CREATE TABLE user (
id SERIAL PRIMARY KEY, -- 自增主键
username VARCHAR(255) NOT NULL UNIQUE, -- 用户名(唯一)
password VARCHAR(255) NOT NULL -- 密码(加密存储)
);

1.2 role 表 ​

存储角色信息。

1
2
3
4
5
CREATE TABLE role (
id SERIAL PRIMARY KEY, -- 自增主键
name VARCHAR(255) NOT NULL UNIQUE -- 角色名称(唯一)
);

1.3 permission 表 ​

存储权限信息。

1
2
3
4
5
6
CREATE TABLE permission (
id SERIAL PRIMARY KEY, -- 自增主键
name VARCHAR(255) NOT NULL UNIQUE, -- 权限名称
description TEXT -- 权限描述
);

1.4 user_roles 表 ​

存储用户与角色的多对多关系。

1
2
3
4
5
6
CREATE TABLE user_roles (
userId INT REFERENCES user(id) ON DELETE CASCADE,
roleId INT REFERENCES role(id) ON DELETE CASCADE,
PRIMARY KEY (userId, roleId)
);

1.5 role_permissions 表 ​

存储角色与权限的多对多关系。

1
2
3
4
5
6
CREATE TABLE role_permissions (
roleId INT REFERENCES role(id) ON DELETE CASCADE,
permissionId INT REFERENCES permission(id) ON DELETE CASCADE,
PRIMARY KEY (roleId, permissionId)
);

1.6 user_permissions 表 ​

存储用户额外分配的权限。

1
2
3
4
5
6
CREATE TABLE user_permissions (
userId INT REFERENCES user(id) ON DELETE CASCADE,
permissionId INT REFERENCES permission(id) ON DELETE CASCADE,
PRIMARY KEY (userId, permissionId)
);

1.7 user_permissions_revoke 表 ​

存储用户被剥夺的权限。

1
2
3
4
5
6
CREATE TABLE user_permissions_revoke (
userId INT REFERENCES user(id) ON DELETE CASCADE,
permissionId INT REFERENCES permission(id) ON DELETE CASCADE,
PRIMARY KEY (userId, permissionId)
);

2. 实体类设计 ​

使用 TypeORM 来定义实体类,分别映射到上述的数据库表。

2.1 User 实体 ​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany, JoinTable } from 'typeorm';
import { Role } from './role.entity';
import { Permission } from './permission.entity';

@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;

@Column({ unique: true })
username: string;

@Column()
password: string;

@ManyToMany(() => Role)
@JoinTable({
name: 'user_roles',
joinColumn: { name: 'userId' },
inverseJoinColumn: { name: 'roleId' },
})
roles: Role[];

@ManyToMany(() => Permission)
@JoinTable({
name: 'user_permissions',
joinColumn: { name: 'userId' },
inverseJoinColumn: { name: 'permissionId' },
})
extraPermissions: Permission[];

@ManyToMany(() => Permission)
@JoinTable({
name: 'user_permissions_revoke',
joinColumn: { name: 'userId' },
inverseJoinColumn: { name: 'permissionId' },
})
revokedPermissions: Permission[];
}

2.2 Role 实体 ​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import { Entity, PrimaryGeneratedColumn, Column, ManyToMany } from 'typeorm';
import { Permission } from './permission.entity';
import { User } from './user.entity';

@Entity()
export class Role {
@PrimaryGeneratedColumn()
id: number;

@Column({ unique: true })
name: string;

@ManyToMany(() => Permission)
@JoinTable({
name: 'role_permissions',
joinColumn: { name: 'roleId' },
inverseJoinColumn: { name: 'permissionId' },
})
permissions: Permission[];

@ManyToMany(() => User, user => user.roles)
users: User[];
}

2.3 Permission 实体 ​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm';

@Entity()
export class Permission {
@PrimaryGeneratedColumn()
id: number;

@Column({ unique: true })
name: string;

@Column()
description: string;
}

3. 服务逻辑 ​

为了获取用户的有效权限,我们需要从数据库中获取角色权限、用户的额外权限和撤销的权限,并进行合并。

3.1 获取用户的有效权限 ​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import { Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { User } from './user.entity';

@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private userRepository: Repository<User>,
) {}

async findOneById(userId: number): Promise<User> {
return this.userRepository.findOne({
where: { id: userId },
relations: ['roles', 'roles.permissions', 'extraPermissions', 'revokedPermissions'],
});
}

async getUserEffectivePermissions(userId: number): Promise<string[]> {
const user = await this.findOneById(userId);
if (!user) {
throw new Error('User not found');
}

const rolePermissions = user.roles.flatMap(role => role.permissions);
const extraPermissions = user.extraPermissions;
const revokedPermissions = user.revokedPermissions;

const effectivePermissions = [
...rolePermissions,
...extraPermissions,
].filter(permission => !revokedPermissions.some(revoked => revoked.id === permission.id));

return [...new Set(effectivePermissions.map(permission => permission.name))];
}
}

4. 权限守卫 &#8203;

为了在控制器中检查权限,我们可以使用 PermissionsGuard 来判断用户是否有执行某操作的权限。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { UserService } from './user.service';

@Injectable()
export class PermissionsGuard implements CanActivate {
constructor(
private reflector: Reflector,
private userService: UserService,
) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const requiredPermissions = this.reflector.get<string[]>('permissions', context.getHandler());
if (!requiredPermissions) {
return true;
}

const request = context.switchToHttp().getRequest();
const user = request.user;

const userPermissions = await this.userService.getUserEffectivePermissions(user.id);

return requiredPermissions.every(permission => userPermissions.includes(permission));
}
}

5. 示例数据 &#8203;

  • 用户 bob 是 editor 角色,有 read_resource 和 edit_resource 权限。

  • 给 bob 额外分配 delete_resource 权限。

  • 撤销 bob 的 edit_resource 权限。

user_permissions 表 &#8203;

1
2
3
4
5
6
+--------+-------------+
| userId | permissionId |
+--------+-------------+
| 2 | 3 | -- bob 额外获得 delete_resource 权限
+--------+-------------+

user_permissions_revoke 表 &#8203;

1
2
3
4
5
6
+--------+-------------+
| userId | permissionId |
+--------+-------------+
| 2 | 2 | -- bob 被撤销了 edit_resource 权限
+--------+-------------+

6. 总结 &#8203;

这个示例展示了如何在 NestJS 和 TypeORM 中设计用户、角色、权限管理系统,支持用户个性化的权限增补和撤销。

以下是一些常见网站的用户角色及其中文和英文名称:

1. 管理员 (Admin) &#8203;

  • 英文: Admin

  • 中文: 管理员

  • 描述: 具有网站或系统的完全访问权限,能够管理所有用户、内容和设置。

2. 超级管理员 (Super Admin) &#8203;

  • 英文: Super Admin

  • 中文: 超级管理员

  • 描述: 拥有比管理员更高的权限,通常可以访问和修改系统的所有方面,包括管理员账户和系统设置。

3. 编辑 (Editor) &#8203;

  • 英文: Editor

  • 中文: 编辑

  • 描述: 可以创建、编辑和发布内容,如文章、帖子或页面,但可能无法管理用户或系统设置。

4. 作者 (Author) &#8203;

  • 英文: Author

  • 中文: 作者

  • 描述: 主要负责创建和管理自己的内容,通常没有权限编辑或删除其他作者的内容。

5. 审核员 (Reviewer) &#8203;

  • 英文: Reviewer

  • 中文: 审核员

  • 描述: 负责审核和批准提交的内容或评论,但不一定有创建或编辑内容的权限。

6. 会员 (Member) &#8203;

  • 英文: Member

  • 中文: 会员

  • 描述: 普通用户,可以访问特定的内容或功能,通常需要注册和登录才能使用。

7. 访客 (Guest) &#8203;

  • 英文: Guest

  • 中文: 访客

  • 描述: 未登录的用户,通常只能查看公开的内容,无法访问会员专属功能或内容。

8. 支持人员 (Support Staff) &#8203;

  • 英文: Support Staff

  • 中文: 支持人员

  • 描述: 负责处理用户问题和请求,可能具有访问用户信息和处理投诉的权限。

9. 操作员 (Operator) &#8203;

  • 英文: Operator

  • 中文: 操作员

  • 描述: 执行特定任务或操作的用户,如数据输入、系统维护等,但没有更高层级的管理权限。

10. 审计员 (Auditor) &#8203;

  • 英文: Auditor

  • 中文: 审计员

  • 描述: 负责检查和审核系统的操作和记录,以确保合规性和安全性,但通常没有修改数据的权限。

这些角色可以根据具体网站的需求进行调整和扩展。例如,电子商务网站可能还会有采购员 (Purchaser)卖家 (Seller) 等角色。

实践检查清单 &#8203;

  • 先确认当前工具链版本和运行环境,再决定是否直接复用示例。
  • 把验证过的最终命令、配置或代码补回本文,减少下次重复排查。
  • 涉及接口、服务端或权限逻辑时,补充失败分支和权限边界测试。

复盘小结 &#8203;

这篇笔记更适合作为问题排查或方案落地前的速查材料。后续如果在真实项目中再次遇到同类问题,可以继续把具体版本、报错信息、最终取舍和验证结果补到对应小节里,让它从代码片段逐步沉淀成完整方案。